/**
 * Created by dev-001 on 2017/3/7.
 */
import * as config from '../config/index';
import path from 'path';
import fs from 'fs';
import * as im from 'imagemagick';
import Exam from '../model/biz/exam';
import Attachment from '../model/sys/attachment';
import Question from '../model/biz/question';
import Clazz from '../model/sys/clazz';
import QuestionGroup from '../model/biz/questionGroup';
import Answer from '../model/biz/answer';
import Student from '../model/sys/user/student';
import Score from '../model/biz/score';
import rq from 'request-promise';
//import * as metrix from '../utils/metrix';
//import _ from 'lodash';
import uuidV1 from 'uuid/v1'
import logger from '../service/logger';
import * as mq from '../mq/index';


function checkAndMake(dir) {
    return mkdirsSync(dir);
}

function mkdirsSync(dir) {
    let exits = fs.existsSync(dir);
    console.log(exits, dir)
    if (exits) {
        return true;
    } else {
        if (mkdirsSync(path.dirname(dir))) {
            fs.mkdirSync(dir);
            return true;
        }
    }
}

async function identifyImg(path) {
    return new Promise((resolve, reject) => {
        im.identify(path, function(err, data) {
            if (err) {
                reject(err)
            } else {
                resolve({width: data.width, height: data.height})
            }
        })
    })
}

/**
 *
 * @param args
 * @returns {Promise.<void>}
 * 切图，由于切图很容易发送错误所以单独切完在处理
 */
export async function autoCrop(args) {
    try {
        logger.trace(args, 'autoCrop');
        let examId = args.examId;
        let dest = args. dest;

        let exam =
            await Exam.findById(examId);
        let questionGroups = await QuestionGroup.find({ exam: examId });
        let examCat = new config.ExamCat(exam._id.toString(), exam.subject.toString());
        logger.trace(exam, 'autoCrop.exam');
        logger.trace(questionGroups, 'autoCrop.questionGroups');
        logger.trace(examCat, 'autoCrop.examCat');

        //获取图片信息
        let sour = dest;
        let imgData = await identifyImg(sour);
        logger.trace(imgData, 'autoCrop.imgData');

        let imgContainer = [], tempId = uuidV1();//临时身份
        logger.trace({tempId}, 'autoCrop.tempId');

        for (let i = 0; i < questionGroups.length; i++) {
            let questionGroup = questionGroups[i];
            logger.trace(questionGroup, `autoCrop.questionGroup[${i}]`);

            //具体每个题组切图目录
            let specificSplitDir = path.join(examCat.examSplit, questionGroup._id.toString());
            checkAndMake(specificSplitDir);
            logger.trace({specificSplitDir}, 'autoCrop.specificSplitDir');

            //切图
            let positions = questionGroup.positions;
            positions[0].x *= imgData.width;positions[0].y *= imgData.height;
            positions[1].x *= imgData.width;positions[1].y *= imgData.height;

            let x1 = positions[0].x, y1 = positions[0].y;
            let width = Math.abs(positions[0].x - positions[1].x);
            let height = Math.abs(positions[0].y - positions[1].y);
            logger.trace({x1, y1, width, height}, 'autoCrop.position');

            let name = uuidV1();//对每个图进行命名，由于上传上来的图片可能会存在名称一样情况，所以这里用一个uuid来作为名字
            let dest = path.join(specificSplitDir, `${name}.jpg`);
            await im.cropImage(sour, dest, {x: x1, y: y1, w: width, h: height});
            logger.trace({ dest }, 'autoCrop.dest');

            imgContainer.push({
                id: questionGroup._id,
                type: questionGroup.type,//区域类型
                name: name,
                dest: config.ExamCat.relative(dest)
            })
        }
        logger.trace(imgContainer, 'autoCrop.imgContainer');

        //通过tmpId来标识出这一批answer是哪位同学的作答，然后通过type可以获取answer中的身份，用来做身份识别，识别后在统一更新user字段
        for(let item of imgContainer) {
            let attachment =
                await Attachment.create({
                    name: item.name,
                    type: 'image/jpeg',
                    path: item.dest
                });
            if(item.type == config.question.type.user || item.type == config.question.type.quser) {
                let userAns = await Answer.create({
                    exam: examId,
                    type: item.type,
                    tempId: tempId,
                    group: item.id,
                    attachment: attachment._id,
                    school: exam.school,
                    grade: exam.grade
                });
                logger.trace(userAns, 'autoCrop.userAns');
            } else {
                let questions = await Question.find({ group: item.id });
                logger.trace(questions, 'autoCrop.questions');

                let _answers = [];
                for(let q of questions) {
                    _answers.push({
                        exam: examId,
                        group: item.id,
                        question: q._id,
                        type: item.type,
                        tempId: tempId,
                        attachment: attachment._id,
                        school: exam.school,
                        grade: exam.grade,
                        status: false
                    });
                let answers = await Answer.create(_answers);
                logger.trace(answers, 'autoCrop.answers');
                }
            }
        }

        //自动打分丢到消息队列中，可以在这里每道题切完只有触发，也可以所有考试试卷都切完后在触发
        //由于切图和打分设计是分离的所以，怎样打分都不会影响，甚至可以重新触发，重新打分
        await mq.producer('autoMarkPeer', { examId, tempId });
        logger.trace({ examId, tempId }, 'autoCrop.autoMarkPeer');
    } catch (e) {
        logger.error(e, 'autoCrop');
    }
}

/**
 *
 * @param args
 * @returns {Promise.<void>}
 * 通常用于针对每道题打分
 */
export async function autoMarkPeer(args) {
    try {
        logger.trace(args, 'autoMarkPeer');

        //获取所有选择题的考试区域
        let { examId, tempId } = args;
        let exam = await Exam.findById(examId);
        let examCat = new config.ExamCat(examId, exam.subject.toString());
        logger.trace(exam, 'autoMarkPeer.exam');
        logger.trace(examCat, 'autoMarkPeer.examCat');

        //首先识别用户
        let userAnswer =
            await Answer.findOne({ tempId: tempId, type: config.question.type.user})
                .populate({
                    path: 'attachment'
                })
                .populate({
                    path: 'group'
                })
        logger.trace(userAnswer, 'autoMarkPeer.userAnswer')

        //请求识别服务
        let body = {
            code: userAnswer.attachment.hostPath,
            col: userAnswer.group.col,
            row: userAnswer.group.row,
            type: 2
        };
        let identityRecogInfo = await rq( {
            method: 'POST',
            uri: 'http://127.0.0.1:20001/studentIdRecog',
            form: body,
            json: true
        });
        logger.trace(identityRecogInfo, 'autoMarkPeer.identityRecogInfo')
        if(!identityRecogInfo.ans) {
            logger.error({body, identityRecogInfo, tempId}, 'autoMarkPeer.identityRecogInfo');
            throw new AbstractError('user cann`t recogn');
        }

        //假如重复上传了，要删除以前上传的answer，暂时关联的图片先不删
        let student = await Student.findOne({ sid: identityRecogInfo.ans });
        if(!student) {
            logger.error({ sid: identityRecogInfo.ans }, 'autoMarkPeer.student');
            return;
        }

        let remIds = await Answer.find({$and: [{ exam: examId, user: student._id}, { tempId: { $ne: tempId}}]}, '_id');
        await Answer.remove({_id: { $in: remIds }});
        await Score.remove({ answer: { $in: remIds }});

        await Answer.update({tempId: tempId}, {user: student._id, clazz: student.clazz }, {multi: true});
        let questionGroups =
            await QuestionGroup.find({ exam: examId, type: { $in: [config.question.type.choice, config.question.type.multiChoice] } });

        for(let group of questionGroups) {
            let questions =
                await Question.find({ group: group._id })
                    .sort({ qid: 1});

            //同一个group中下面所有的题目存的图片都是同一个，所以就任取一个answer获取图片就可以
            let answer =
                await Answer.findOne({
                    question: questions[0]._id
                }).populate({
                    path: 'attachment'
                })
            let col = group.optionsNo;
            let row = group.ranges.length;
            if (group.direction == config.question.direction.vertical) {
                let tmp = col;
                col = row;
                row = tmp;
            }
            //识别
            let userAnswers = await rq( {
                method: 'POST',
                uri: 'http://127.0.0.1:20001/recog',
                form: {
                    card: answer.attachment.hostPath,
                    col: col,
                    row: row,
                },
                json: true
            });
            logger.trace(userAnswers, 'autoMarkPeer.userAnswers');

            //都置换成水平
            let data = group.direction == 1 ? userAnswers.ans : metrix.transpose(userAnswers.ans);//都变成水平
            logger.trace(data, 'autoMarkPeer.finalUserAnswers');

            for(let [index, question] of questions.entries()) {
                let answer = await Answer.findOne({ user: student._id, question: question._id });

                let userAns = [];
                let standardAns = question.answer.split(/\||,/).map((ans) => {return ans.toUpperCase()});
                //打分
                    for(let [i, ans] of data[index].entries()) {
                        if(ans == 1) {
                            userAns.push(String.fromCharCode(65 + i));
                        }
                    }
                    let score = 0;
                    if(_.intersection(userAns, standardAns)) {
                       let rightNum = 0;
                       let wrongNum = 0;
                        for(let ans of userAns) {
                            if(!standardAns.includes(ans)) {
                                ++wrongNum;
                            }else {
                                ++rightNum;
                            }
                        }

                        score = wrongNum > 0 ? 0 : (rightNum == standardAns.length ? question.score : question.score/2);
                    }
                    await Score.create({
                        answer: answer._id,
                        user: answer.user,
                        score: score
                    });

                    await answer.update({
                        content: userAns,
                        score: score,
                        status: true,
                        points: question.points,
                        ability: question.abilities
                    });
                    logger.trace({qid: question.qid, user: student._id, content: userAns}, 'autoMarkPeer.userSelectAnswers');
            }
       }
    } catch (e) {
        logger.error(e, 'autoMarkPeer');
    }
}

/**
 *
 * @param args
 * @returns {Promise.<void>}
 * 通常用于对所有题进行打分，
 * 比如可能识别出问题，需要重新打分
 */
export async function autoMarkAll(args) {
    try {
        //todo
    } catch (e) {
        console.log(e);
    }
}